home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / misc / emu / msh-156.lha / dev / devio1.a < prev    next >
Text File  |  1996-12-22  |  20KB  |  732 lines

  1. ;;;;
  2. ;
  3. ; $Id: devio1.a,v 1.56 1996/12/21 23:34:35 Rhialto Rel $
  4. ; $Log: devio1.a,v $
  5. ; Revision 1.56  1996/12/21  23:34:35  Rhialto
  6. ; No changes.
  7. ;
  8. ; Revision 1.55  1993/12/30  22:45:10  Rhialto
  9. ; Remove hardware constants (are now in c.i).
  10. ; Trackbuffer is a pointer now instead of an array.
  11. ; Freeze for MAXON5.
  12. ;
  13. ; Revision 1.54  1993/06/24  04:56:00  Rhialto
  14. ; DICE 2.07.54R.
  15. ;
  16. ; Revision 1.53  92/10/25  02:11:43  Rhialto
  17. ; No change.
  18. ;
  19. ; Revision 1.51  92/04/17  15:42:25  Rhialto
  20. ; Freeze for MAXON3. Change cyl+side units to track units.
  21. ;
  22. ; Revision 1.47  91/11/03  01:08:02  Rhialto
  23. ; Load A0 with custom address in interrupt code since that value is
  24. ; not guaranteed already there.
  25. ;
  26. ; Revision 1.46  91/10/06  18:27:12  Rhialto
  27. ;
  28. ; Freeze for MAXON
  29. ;
  30. ; Revision 1.44  91/10/02  21:06:58  Rhialto
  31. ; Fix bug that sectors with number 0 are accepted and crash.
  32. ;
  33. ; Revision 1.43  91/09/28  01:31:11  Rhialto
  34. ; Split out asm for DICE conversion.
  35. ;
  36. ; Revision 1.42  91/06/14  00:04:44  Rhialto
  37. ; DICE conversion
  38. ;
  39. ; Revision 1.40  91/03/03  17:56:00  Rhialto
  40. ; Freeze for MAXON
  41. ;
  42.  
  43.     section     text,code
  44.     include     "c.i"
  45.  
  46. ; Some hardware addresses:
  47.  
  48.         xdef _custom
  49. _custom     equ $DFF000
  50.  
  51. Dsklen        equ $24
  52. Intena        equ $9a     ; Interrupt enable  register (write)
  53. Intreq        equ $9c     ; Interrupt request register (write)
  54.  
  55.         xdef _ciab
  56. _ciab        equ $BFD000
  57.  
  58. ; Flags in DSKLEN:
  59.  
  60. dskdmaoff    equ $4000
  61.  
  62. ; Flags in INTENA/INTREQ:
  63.  
  64. intf_setclr    equ    1<<15
  65. intf_dskblk    equ    1<<1
  66.  
  67. ; CIA interrupt control register bits/flags:
  68.  
  69. ciaicrf_flg    equ    1<<4    ; flg interrupt (disk index)
  70.  
  71. ; some cia.resource library functions
  72.  
  73.     xref    _LVOSignal
  74.     xref    _LVOAbleICR
  75.     xref    _LVOSetICR
  76.     xref    _CiaBResource
  77.  
  78.     xdef     _SafeEnableICR
  79. _SafeEnableICR:             ; the argument is passed as a long for now
  80.     move.l    a6,-(sp)
  81.     move.l    _CiaBResource,a6
  82.     move.l    4+4(sp),d0          ; skip a6,retadr
  83.     jsr    _LVOSetICR(a6)      ; clear pending interrupt
  84.     move.l    4+4(sp),d0          ; skip a6,retadr
  85.     or.b    #$80,d0         ; then enable it
  86.     jsr    _LVOAbleICR(a6)
  87.     move.l    (sp)+,a6
  88.     rts
  89. ;;;;
  90. ;
  91. ;   Disk index interrupt code.
  92. ;   is_Data (A1) is the value to stuff into the DSKLEN register.
  93. ;   It then enables the disk block interrupt and disables the
  94. ;   index interrupt.
  95.  
  96.     xdef    _IndexIntCode
  97. _IndexIntCode:
  98.     lea    _custom,a0        ; not guaranteed already there
  99.     move.w    #dskdmaoff,Dsklen(a0)
  100.     move.w    a1,Dsklen(a0)
  101.     move.w    a1,Dsklen(a0)       ; this enables the DMA
  102.     move.w    #intf_setclr|intf_dskblk,Intena(a0)
  103.     move.l    _CiaBResource,a6
  104.     move.b    #ciaicrf_flg,d0
  105.     jsr    _LVOAbleICR(a6)     ; disable index interrupt
  106.     rts
  107. ;;;;
  108. ;
  109. ;   Disk DMA finished interrupt code.
  110. ;   (a1) is the task to Signal, 4(a1) is the signal mask to use.
  111. ;   Disables the disk block finished interrupt.
  112.  
  113.     xdef    _DskBlkIntCode
  114. _DskBlkIntCode:
  115.     lea    _custom,a0        ; not guaranteed already there
  116.     move.w    #dskdmaoff,Dsklen(a0)   ; disable disk DMA
  117.     move.w    #intf_dskblk,Intena(a0) ; disable the interrupt
  118.     move.w    #intf_dskblk,Intreq(a0) ; clear 'diskblock finished' flag
  119.     move.l    4(a1),d0            ; signal mask
  120.     move.l    (a1),a1             ; task to signal
  121.     jsr    _LVOSignal(a6)
  122.     rts
  123.  
  124.  
  125. ;;;;
  126. ;
  127. ; Create missing bindings
  128. ;
  129.  
  130.         xref    _DRResource
  131.  
  132. lib_vectsize    equ    6
  133. lib_base    equ    -lib_vectsize
  134.  
  135. _RVOAllocUnit    equ    lib_base-(0*lib_vectsize)
  136. _RVOFreeUnit    equ    lib_base-(1*lib_vectsize)
  137. _RVOGetUnit    equ    lib_base-(2*lib_vectsize)
  138. _RVOGiveUnit    equ    lib_base-(3*lib_vectsize)
  139. _RVOGetUnitID    equ    lib_base-(4*lib_vectsize)
  140.  
  141. ;_AllocUnit:
  142. ;    move.l    4(sp),d0
  143. ;@AllocUnit:
  144. ;    move.l    a6,-(sp)
  145. ;    move.l    _DRResource,a6
  146. ;    jsr    _RVOAllocUnit(a6)
  147. ;    move.l    (sp)+,a6
  148. ;    rts
  149.  
  150. ;_FreeUnit:
  151. ;    move.l    4(sp),d0
  152. ;@FreeUnit:
  153. ;    move.l    a6,-(sp)
  154. ;    move.l    _DRResource,a6
  155. ;    jsr    _RVOFreeUnit(a6)
  156. ;    move.l    (sp)+,a6
  157. ;    rts
  158.  
  159.     xdef    _GetUnit,@GetUnit
  160. _GetUnit:
  161.     move.l    4(sp),a1
  162. @GetUnit:
  163.     move.l    a6,-(sp)
  164.     move.l    _DRResource,a6
  165.     jsr    _RVOGetUnit(a6)
  166.     move.l    (sp)+,a6
  167.     rts
  168.  
  169. ;_GetUnitID:
  170. ;    move.l    4(sp),d0
  171. ;@GetUnitID:
  172. ;    move.l    a6,-(sp)
  173. ;    move.l    _DRResource,a6
  174. ;    jsr    _RVOGetUnitID(a6)
  175. ;    move.l    (sp)+,a6
  176. ;    rts
  177.  
  178.     xdef    _GiveUnit
  179. _GiveUnit:
  180.     move.l    a6,-(sp)
  181.     move.l    _DRResource,a6
  182.     jsr    _RVOGiveUnit(a6)
  183.     move.l    (sp)+,a6
  184.     rts
  185.  
  186. ;;;;
  187. ;
  188. ;   Macro to decode a single MFM word to a byte.
  189. ;   Auto-increments the rawbuffer pointer.
  190. ;
  191. ;   Also provided as subroutine later on, for decoding that doesn't
  192. ;   need to be inline.
  193.  
  194. decode    macro
  195.     move.b    (rawbuf)+,d1    ; high nybble
  196.     and.w    #$7f,d1     ; strip clock bit (and garbage)
  197.     move.b    0(decode,d1.w),d0; decode 4 data bits
  198.     lsl.b    #4,d0        ; make room for the rest
  199.  
  200.     move.b    (rawbuf)+,d1    ; low nybble
  201.     and.b    #$7f,d1     ; strip clock bit again
  202.     or.b    0(decode,d1.w),d0; insert 4 decoded bits
  203.  
  204.     endm
  205.  
  206. ;int
  207. ;DecodeTrack0(dev, unit)
  208. ;DEV        *dev;
  209. ;UNIT        *unit;
  210. ;{
  211.     xdef    _DecodeTrack0
  212. _DecodeTrack0:
  213.  
  214. dtregs    reg    a2/a3/a4/d3
  215.  
  216.     movem.l dtregs,-(sp)
  217.     link    a5,#-20
  218.  
  219. ;    register byte  *secptr;                 /*  a4 */
  220. ;    long         sector;
  221. ;    word         numsecs;
  222. ;    register long   numbytes;                 /*  d3 */
  223. ;    word         maxsec;
  224.  
  225.  
  226. MFM_ID        equ     $5554
  227. MFM_DATA    equ     $5545
  228.  
  229. rawbuf        equr    a2
  230. decode        equr    a3
  231. secptr        equr    a4
  232. numbytes    equr    d3
  233.  
  234. dev        set     8+(4*4)
  235. unit        set     12+(4*4)
  236.  
  237. rawend        set     -4
  238. trackbuf    set     -8
  239. oldcrc        set     -12
  240. sector        set     -16
  241. numsecs     set     -18
  242. maxsec        set     -20
  243.  
  244.     move.l    dev(a5),a0
  245. ; word    *rawbuf = (word *)dev->md_Rawbuffer;
  246.     move.l    md_Rawbuffer(a0),rawbuf
  247.  
  248. ; byte *decode = dev->md_MfmDecode;
  249.     lea    md_MfmDecode(a0),decode
  250.  
  251.     move.l    unit(a5),a0
  252. ; word *rawend = (byte *)rawbuf + unit->mu_ReadLen - (MS_BPS+2)*sizeof(word);
  253.     move.w    mu_ReadLen(a0),d0       ; mu_ReadLen
  254.     lea    0(rawbuf,d0.w),a1       ; rawbuf + mu_ReadLen
  255.     suba.w    #(MS_BPS+2)*2,a1        ; - (MS_BPS+2)*sizeof(word)
  256.     move.l    a1,rawend(a5)           ; rawend =
  257.  
  258. ; byte    *trackbuf = unit->mu_TrackBuffer;
  259.     move.l    mu_TrackBuffer(a0),a1
  260.     move.l    a1,trackbuf(a5)
  261.  
  262. ; word *oldcrc = unit->mu_CrcBuffer;
  263.     lea    mu_CrcBuffer(a0),a1
  264.     move.l    a1,oldcrc(a5)
  265.  
  266.     move.w    #0,numsecs(a5)      ; no sectors found yet
  267.     move.w    #0,maxsec(a5)       ; and no highest sector number
  268.  
  269. ;;;;    First we will try to find a sector id.
  270. find_id:
  271.     movea.l rawend(a5),a0       ; preload often-used values
  272.     move.w    #SYNC,d0
  273. find_id2:
  274.     cmp    (rawbuf)+,d0
  275.     beq.s    fid_gotsync
  276.     cmpa.l    a0,rawbuf        ; compare with end of buffer
  277.     blt.s    find_id2
  278.     bra    return            ; We ran off the end of the buffer.
  279.  
  280. fid_gotsync:                ; Skip the other syncs.
  281.     cmp.w    (rawbuf),d0
  282.     bne.s    fid_endsync
  283.     lea    2(rawbuf),rawbuf
  284.     bra.s    fid_gotsync
  285.  
  286. fid_endsync:
  287.     cmp.w    #MFM_ID,(rawbuf)+
  288.     bne.s    find_id
  289.  
  290. ;     bsr     DecodeByte         ; cylinder #
  291. ;     bsr     DecodeByte         ; side #
  292.     adda    #4,rawbuf        ; skip cylinder and side #
  293.     moveq.l #0,d0            ; clear high part
  294.     bsr    DecodeByte        ; sector #
  295.     tst.w    d0
  296.     beq.s    find_id         ; sector number too small (0)?
  297.     cmp.w    #MS_SPT_MAX,d0        ; sector number too large?
  298.     bgt.s    find_id
  299.     cmp.w    maxsec(a5),d0       ; what is the highest sector number?
  300.     ble.s    nomax
  301.     move.w    d0,maxsec(a5)       ; record the highest sector number
  302. nomax:
  303.     subq.w    #1,d0            ; normalise sector number
  304.     move.l    d0,sector(a5)
  305.  
  306. find_data:                ; Then find the data block.
  307.     movea.l rawend(a5),a0       ; preload often-used values
  308.     move.w    #SYNC,d0
  309.  
  310. find_data2:
  311.     cmp.w    (rawbuf)+,d0
  312.     beq.s    fda_gotsync
  313.     cmpa.l    a0,rawbuf
  314.     blt.s    find_data2
  315.     bra.s    return            ; we ran off the end of the buffer.
  316.  
  317. fda_gotsync:                ; skip the other syncs.
  318.     cmp.w    (rawbuf),d0
  319.     bne.s    fda_endsync
  320.     lea    2(rawbuf),rawbuf
  321.     bra.s    fda_gotsync
  322.  
  323. fda_endsync:
  324.     cmp.w    #MFM_DATA,(rawbuf)+ ; do we really have a data block?
  325.     bne.s    find_id
  326.  
  327.     cmpa.l    a0,rawbuf        ; will we still be inside the mfm data?
  328.     bge.s    return
  329.  
  330.     move.l    sector(a5),d0       ; calculate the location to
  331.     moveq.l #LOG2_MS_BPS,d1     ;  store this sector.
  332.     asl.l    d1,d0
  333.     move.l    trackbuf(a5),secptr
  334.     add.l    d0,secptr
  335.  
  336.     move.w    #MS_BPS-1,numbytes
  337. data_copy:                ; decode the contents of the sector
  338. ;     bsr.s     DecodeByte
  339.     decode
  340.     move.b    d0,(secptr)+
  341.     dbra    numbytes,data_copy
  342.  
  343.     move.l    sector(a5),d3       ; get pointer to crc location
  344.     add.l    d3,d3            ; 2 bytes of crc per sector
  345.     move.l    oldcrc(a5),a0
  346.     add.l    d3,a0
  347.  
  348.     bsr.s    DecodeByte        ; get high byte
  349.     move.b    d0,(a0)+
  350.     bsr.s    DecodeByte        ; and low byte of crc
  351.     move.b    d0,(a0)+
  352.  
  353. ;;;;    unit->mu_SectorStatus[sector] = unit->mu_InitSectorStatus;
  354.     move.l    unit(a5),a0
  355.     move.b    mu_InitSectorStatus(a0),d0
  356.     move.w    sector+2(a5),d1
  357.     lea    mu_SectorStatus(a0),a0
  358.     move.b    d0,0(a0,d1.w)
  359.  
  360.     addq.w    #1,numsecs(a5)
  361.     cmp.w    #MS_SPT_MAX,numsecs(a5)
  362.     blt    find_id
  363.  
  364. return:
  365.     move.w    maxsec(a5),d0
  366.     unlk    a5
  367.     movem.l (sp)+,dtregs
  368.     rts
  369.  
  370. ;;;;
  371. ;
  372. ;   Subroutine version of decode macro.
  373.  
  374. DecodeByte:
  375.     decode
  376.     rts
  377.  
  378.     ifeq    READONLY
  379.  
  380. ;;;;
  381. ;
  382. ;   Macro to encode a single byte to MFM.
  383. ;
  384. ;   Also provided as a subroutine later on, for encoding that
  385. ;   doesn't need to be inline.
  386. ;
  387. ;   putmfm encodes one byte (in D0) into MSDOS MFM format to the location
  388. ;   pointed by A0. D3 has to be preserved between calls !
  389. ;   A2 must contain the pointer to the encoding table.
  390. ;   Destroys D0, D1. Updates A0 and D3. Requires A0, D0, D3.
  391.  
  392. putmfm    macro
  393. ;     and.w     #$FF,d0    ; assume d0.w is clean
  394.     lsl.w    #1,d0        ; we make things twice as big here
  395.     move.w    0(a2,d0.w),d1   ; get mfm encoded byte from table
  396.     btst    #14,d1        ; we now have to work out if
  397.     bne.s    1$        ; the high bit of the unencoded data
  398.     btst    #0,d3        ; byte and the low bit of the last
  399.     bne.s    1$        ; encoded data are both 0. if this is the
  400.     bset    #15,d1        ; case the first clock bit has to be '1'
  401. 1$    move.w    d1,(a0)+        ; write encoded byte
  402.     move.w    d1,d3
  403.     endm
  404.  
  405. ; we need a buffer for the Sector-ID field to calculate its checksum
  406. ;SectorHeader:
  407. ;    dc.b    0          ; cylinder
  408. ;    dc.b    0          ; side
  409. ;    dc.b    0          ; sector
  410. ;    dc.b    2          ; length (2=512 bytes)
  411. ;    dc.w    0          ; CRC
  412.  
  413.     xref    _MfmEncode
  414.     xref    _MfmEncodeWord
  415.     xdef    _EncodeTrack
  416.  
  417. ;;;;
  418. ;
  419. ;   EncodeTrack(TrackBuffer, Rawbuffer, Crcs, Cylinder, Side, GapLen, NumSecs,
  420. ;        4         4        4     2 of 4    2(/4) 2(/4)   2(/4)
  421. ;        WriteLen)
  422. ;        2(/4)
  423.  
  424. _EncodeTrack:
  425.     movem.l D2-D7/A2-A6,-(sp)  ; save registers
  426.  
  427. fp    set    (4*(6+5))+4        ; 4 for return address
  428. trackbf set    0
  429. rawbf    set    4
  430. crcs    set    8
  431. cylinder   set    12
  432. side    set    16
  433. gaplen    set    20
  434. numsecs set    24
  435. wlen    set    28
  436.  
  437. ; a0    ptr in encoded data (also putmfmbyte)
  438. ; a2    ptr to mfm encoding table (putmfmbyte)
  439. ; a3    ptr to data to be crc'd (HeaderCRC)
  440. ; a4    ptr to table with calculated CRC's
  441. ; a5    ptr to unencoded data
  442.  
  443. ; d0    byte to be encoded (putmfmbyte)
  444. ; d1    trashed by putmfmbyte
  445. ; d3    used by putmfmbyte
  446. ; d5    sector number
  447. ; d6    general counter of byte spans
  448. ; d7    sector countdown
  449.  
  450.     sub.w    #2,fp+gaplen+2(sp) ; gap length between sectors
  451.     move.l    fp+rawbf(sp),a0    ; pointer to mfmencoded buffer
  452.     move.l    fp+crcs(sp),a4     ; pointer to precalculated CRCs
  453.     move.l    fp+trackbf(sp),a5  ; pointer to unencoded data
  454.     lea    _MfmEncodeWord,a2      ; pointer to MFM lookup table
  455.  
  456.     move.w    #$9254,d0       ; a track starts with a gap ($4e)
  457.     moveq    #INDEXGAP-1,d6
  458. ingl1    move.w    d0,(a0)+           ; mfmencoded = $9254
  459.     dbf    d6,ingl1
  460.  
  461.     move.w    #$aaaa,d0       ; a track index starts with a gap containing
  462.     moveq    #INDXGAP-1,d6       ; 12 * 0 (mfm = $aaaa)
  463. ingl2    move.w    d0,(a0)+
  464.     dbf    d6,ingl2
  465.  
  466.     move.w    #INDEXSYNC,d0       ; The INDEX field begins here, starting
  467.     move.w    d0,(a0)+           ; with 3 syncs (3 * $c2) with a missing
  468.     move.w    d0,(a0)+           ; clock bit
  469.     move.w    d0,(a0)+
  470.  
  471.     move.w    #$5552,(a0)+       ; INDEX mark ($fc)
  472.  
  473.     move.w    #$9254,d0       ; more gap
  474.     moveq    #INDEXGAP2-1,d6
  475. ingl3    move.w    d0,(a0)+           ; mfmencoded = $9254
  476.     dbf    d6,ingl3
  477.  
  478.     lea    -6(sp),sp          ; Reserve room for SectorHeader
  479. fp    set    fp+6
  480.     move.w    fp+numsecs+2(sp),d7; number of sectors to encode
  481.     subq.w    #1,d7           ; minus 1 for dbra
  482.     moveq    #0,d5           ; start with first sector
  483.  
  484. secloop:
  485.     move.w    #$aaaa,d0       ; a sector starts with a gap containing
  486.     moveq    #IDGAP2-1,d6       ; 12 * 0 (mfm = $aaaa)
  487. id2gl    move.w    d0,(a0)+
  488.     dbf    d6,id2gl
  489.  
  490.     move.w    #SYNC,d0       ; The ID field begins here, starting
  491.     move.w    d0,(a0)+           ; with 3 syncs (3 * $a1) with a missing
  492.     move.w    d0,(a0)+           ; clock bit
  493.     move.w    d0,(a0)+
  494.  
  495.     move.w    #$5554,(a0)+       ; ID-Address mark ($fe)
  496.  
  497.     move.l    sp,a3           ; pointer to Sector-ID buffer
  498.  
  499.     moveq    #$5554&1,d3       ; preload d3 for the putmfmbyte routine
  500.     move.b    fp+cylinder+3(sp),0(a3)  ; insert current cylinder number
  501.     move.b    fp+side+3(sp),1(a3)   ; side number
  502.     addq.w    #1,d5           ; sectors start with 1 instead of 0
  503.     move.b    d5,2(a3)           ; sector number
  504.     move.b    #MS_BPScode,3(a3)  ; sector length 512 bytes
  505.     bsr    HeaderCRC       ; calculate checksum
  506.     move.w    d0,IDDATA(a3)      ; put it past the data
  507.  
  508.     moveq    #IDDATA+IDCRC-1,d6 ; 6 bytes Sector-ID
  509. sidl    move.b    (a3)+,d0           ; get one byte
  510.     bsr    putmfmbyte       ; encode it
  511.     dbf    d6,sidl        ; end of buffer ?
  512.  
  513.     moveq    #$4e,d0        ; recalculate the MFM value of the
  514.     bsr    putmfmbyte       ; first gap byte
  515.  
  516.     moveq    #DATAGAP1-1-1,d6   ; GAP consisting of
  517.     move.w    #$9254,d0       ; 22 * $4e
  518. dg1l    move.w    d0,(a0)+
  519.     dbf    d6,dg1l
  520.  
  521.     moveq    #DATAGAP2-1,d6       ; GAP consisting of
  522.     move.w    #$aaaa,d0       ; 12 * 0 (mfm = $aaaa)
  523. dg2l    move.w    d0,(a0)+
  524.     dbf    d6,dg2l
  525.  
  526.     move.w    #SYNC,d0       ; Sector data
  527.     move.w    d0,(a0)+           ; starts with 3 syncs
  528.     move.w    d0,(a0)+
  529.     move.w    d0,(a0)+
  530.  
  531.     move.w    #$5545,(a0)+       ; Data Address Mark ($fb)
  532.  
  533.     moveq    #$5545&1,d3       ; preload d3
  534.     move    #MS_BPS-1,d6       ; a sector has 512 bytes
  535. dblockl moveq    #0,d0           ; avoid garbage
  536.     move.b    (a5)+,d0           ; get one byte from the buffer
  537. ;     bsr.s     putmfmbyte        ; encode it
  538.     putmfm
  539.     dbf    d6,dblockl       ; end of sector ?
  540.  
  541.     move.b    (a4)+,d0           ; get first byte of CRC
  542.     bsr.s    putmfmbyte       ; encode it
  543.     move.b    (a4)+,d0           ; get second byte
  544.     bsr.s    putmfmbyte       ; encode it
  545.  
  546.     moveq    #$4e,d0        ; recalculate the MFM value of the
  547.     bsr.s    putmfmbyte       ; first gap byte -> -1 in following loop
  548.  
  549.     move.w    fp+gaplen+2(sp),d6 ; sector ends with a gap, -1 for dbf
  550.     move.w    #$9254,d0       ; 80 * $4e
  551. dg3l    move.w    d0,(a0)+
  552.     dbf    d6,dg3l
  553.  
  554.     dbf    d7,secloop       ; next sector. d5 has been incremented
  555.  
  556.     lea    6(sp),sp           ; Free room for SectorHeader
  557. fp    set    fp-6
  558.  
  559.     move.l    fp+rawbf(sp),d6    ; pointer to mfmencoded buffer
  560.     add.l    fp+wlen(sp),d6     ; end of encoded buffer
  561.     subq.l    #2,d6           ; -2 for dbf
  562.     move.l    a0,d0           ; (I really want to   sub.l a0,d6 )
  563.     sub.l    d0,d6           ; length of the remains
  564.     lsr.l    #1,d6           ; turn into words
  565.  
  566.     move.w    #$9254,d0       ; Fill the end of the track with $4e
  567. endgl    move.w    d0,(a0)+           ; $9254 mfm encoded
  568.     dbf    d6,endgl
  569.  
  570.     movem.l (sp)+,D2-D7/A2-A6
  571.     rts
  572.  
  573. ;;;;
  574. ;
  575. ;   putmfmbyte
  576. ;
  577. ;   Subroutine version of the macro. Same register conventions, of course.
  578.  
  579. putmfmbyte:
  580.     and.w    #$FF,d0     ; strip garbage
  581.     putmfm
  582.     rts
  583.  
  584.     endc    ; ifne READONLY
  585.  
  586. ;;;;
  587. ;
  588. ; The CRC is computed not only over the actual data, but including
  589. ; the SYNC mark (3 * $a1) and the 'ID/DATA - Address Mark' ($fe/$fb).
  590. ; As we don't read or encode these fields into our buffers, we have to
  591. ; preload the registers containing the CRC with the values they would have
  592. ; after stepping over these fields.
  593. ;
  594. ; How CRCs "really" work:
  595. ;
  596. ; First, you should regard a bitstring as a series of coefficients of
  597. ; polymomials. We calculate with these polynomials in modulo-2
  598. ; arithmetic, in which both add and subtract are done the same as
  599. ; exclusive-or. Now, we modify our data (a very long polynomial) in
  600. ; such a way that it becomes divisible by the CCITT-standard 16-bit
  601. ;         16   12   5
  602. ; polynomial:    x  + x    + x + 1, represented by $11021. The easiest
  603. ; way to do this would be to multiply (using proper arithmetic) our
  604. ; datablock with $11021. So we have:
  605. ;   data * $11021         =
  606. ;   data * ($10000 + $1021)      =
  607. ;   data * $10000 + data * $1021
  608. ; The left part of this is simple: Just add two 0 bytes. But then
  609. ; the right part (data $1021) remains difficult and even could have
  610. ; a carry into the left part. The solution is to use a modified
  611. ; multiplication, which has a result that is not correct, but with
  612. ; a difference of any multiple of $11021. We then only need to keep
  613. ; the 16 least significant bits of the result.
  614. ;
  615. ; The following algorithm does this for us:
  616. ;
  617. ;   unsigned char *data, c, crclo, crchi;
  618. ;   while (not done) {
  619. ;    c = *data++ + crchi;
  620. ;    crchi = (@ c) >> 8 + crclo;
  621. ;    crclo = @ c;
  622. ;   }
  623. ;
  624. ; Remember, + is done with EOR, the @ operator is in two tables (high
  625. ; and low byte separately), which is calculated as
  626. ;
  627. ;      $1021 * (c & $F0)
  628. ;  xor $1021 * (c & $0F)
  629. ;  xor $1021 * (c >> 4)         (* is regular multiplication)
  630. ;
  631. ;
  632. ; Anyway, the end result is the same as the remainder of the division of
  633. ; the data by $11021. I am afraid I need to study theory a bit more...
  634.  
  635.  
  636. ; This is the entry to calculate the checksum for the sector-id field
  637. ; requires:  a3 = pointer to the unencoded data
  638. ; returns:   d0 = CRC
  639.  
  640. HeaderCRC:
  641.     movem.l  D1-D3/A3-A5,-(sp) ; save registers
  642.     move.w     #$b2,d0       ; preload registers
  643.     moveq     #$30,d1       ; (CRC for $a1,$a1,$a1,$fb)
  644.     moveq     #3,d3           ; calculate checksum for 4 bytes
  645.     bra.s     getCRC        ; (=cylinder,side,sector,sectorlength)
  646.  
  647. ; This is the entry to calculate the checksum for the data field
  648. ; requires:  a3 = pointer to the unencoded data
  649. ; returns:   d0 = CRC
  650.  
  651. ; C entry point for DataCRC(byte *data)
  652.  
  653.     xdef    _DataCRC
  654. _DataCRC:
  655.     movem.l D1-D3/A3-A5,-(sp)  ; save registers
  656. fp    set    (4*(3+3))+4
  657. data    set    0
  658.     move.l    fp+data(sp),a3     ; get parameter
  659.     move.w    #$e2,d0        ; preload the CRC registers
  660.     move.w    #$95,d1        ; (CRC for $a1,$a1,$a1,$fe)
  661.     move.w    #MS_BPS-1,d3       ; a sector 512 bytes
  662.  
  663. getCRC    lea    CRCTable1(pc),a4
  664.     lea    CRCTable2(pc),a5
  665.     moveq    #0,d2
  666.  
  667. 1$    move.b    (a3)+,d2
  668.     eor.b    d0,d2
  669.     move.b    0(a4,d2.w),d0
  670.     eor.b    d1,d0
  671.     move.b    0(a5,d2.w),d1
  672.     dbf    d3,1$
  673.  
  674.     lsl.w    #8,d0           ; merge both halves of the CRC
  675.     move.b    d1,d0
  676.     movem.l (sp)+,D1-D3/A3-A5
  677.     rts
  678.  
  679. CRCTable1:
  680.     dc.b $00,$10,$20,$30,$40,$50,$60,$70,$81,$91,$a1,$b1,$c1,$d1,$e1,$f1
  681.     dc.b $12,$02,$32,$22,$52,$42,$72,$62,$93,$83,$b3,$a3,$d3,$c3,$f3,$e3
  682.     dc.b $24,$34,$04,$14,$64,$74,$44,$54,$a5,$b5,$85,$95,$e5,$f5,$c5,$d5
  683.     dc.b $36,$26,$16,$06,$76,$66,$56,$46,$b7,$a7,$97,$87,$f7,$e7,$d7,$c7
  684.     dc.b $48,$58,$68,$78,$08,$18,$28,$38,$c9,$d9,$e9,$f9,$89,$99,$a9,$b9
  685.     dc.b $5a,$4a,$7a,$6a,$1a,$0a,$3a,$2a,$db,$cb,$fb,$eb,$9b,$8b,$bb,$ab
  686.     dc.b $6c,$7c,$4c,$5c,$2c,$3c,$0c,$1c,$ed,$fd,$cd,$dd,$ad,$bd,$8d,$9d
  687.     dc.b $7e,$6e,$5e,$4e,$3e,$2e,$1e,$0e,$ff,$ef,$df,$cf,$bf,$af,$9f,$8f
  688.     dc.b $91,$81,$b1,$a1,$d1,$c1,$f1,$e1,$10,$00,$30,$20,$50,$40,$70,$60
  689.     dc.b $83,$93,$a3,$b3,$c3,$d3,$e3,$f3,$02,$12,$22,$32,$42,$52,$62,$72
  690.     dc.b $b5,$a5,$95,$85,$f5,$e5,$d5,$c5,$34,$24,$14,$04,$74,$64,$54,$44
  691.     dc.b $a7,$b7,$87,$97,$e7,$f7,$c7,$d7,$26,$36,$06,$16,$66,$76,$46,$56
  692.     dc.b $d9,$c9,$f9,$e9,$99,$89,$b9,$a9,$58,$48,$78,$68,$18,$08,$38,$28
  693.     dc.b $cb,$db,$eb,$fb,$8b,$9b,$ab,$bb,$4a,$5a,$6a,$7a,$0a,$1a,$2a,$3a
  694.     dc.b $fd,$ed,$dd,$cd,$bd,$ad,$9d,$8d,$7c,$6c,$5c,$4c,$3c,$2c,$1c,$0c
  695.     dc.b $ef,$ff,$cf,$df,$af,$bf,$8f,$9f,$6e,$7e,$4e,$5e,$2e,$3e,$0e,$1e
  696.  
  697. CRCTable2:
  698.     dc.b $00,$21,$42,$63,$84,$a5,$c6,$e7,$08,$29,$4a,$6b,$8c,$ad,$ce,$ef
  699.     dc.b $31,$10,$73,$52,$b5,$94,$f7,$d6,$39,$18,$7b,$5a,$bd,$9c,$ff,$de
  700.     dc.b $62,$43,$20,$01,$e6,$c7,$a4,$85,$6a,$4b,$28,$09,$ee,$cf,$ac,$8d
  701.     dc.b $53,$72,$11,$30,$d7,$f6,$95,$b4,$5b,$7a,$19,$38,$df,$fe,$9d,$bc
  702.     dc.b $c4,$e5,$86,$a7,$40,$61,$02,$23,$cc,$ed,$8e,$af,$48,$69,$0a,$2b
  703.     dc.b $f5,$d4,$b7,$96,$71,$50,$33,$12,$fd,$dc,$bf,$9e,$79,$58,$3b,$1a
  704.     dc.b $a6,$87,$e4,$c5,$22,$03,$60,$41,$ae,$8f,$ec,$cd,$2a,$0b,$68,$49
  705.     dc.b $97,$b6,$d5,$f4,$13,$32,$51,$70,$9f,$be,$dd,$fc,$1b,$3a,$59,$78
  706.     dc.b $88,$a9,$ca,$eb,$0c,$2d,$4e,$6f,$80,$a1,$c2,$e3,$04,$25,$46,$67
  707.     dc.b $b9,$98,$fb,$da,$3d,$1c,$7f,$5e,$b1,$90,$f3,$d2,$35,$14,$77,$56
  708.     dc.b $ea,$cb,$a8,$89,$6e,$4f,$2c,$0d,$e2,$c3,$a0,$81,$66,$47,$24,$05
  709.     dc.b $db,$fa,$99,$b8,$5f,$7e,$1d,$3c,$d3,$f2,$91,$b0,$57,$76,$15,$34
  710.     dc.b $4c,$6d,$0e,$2f,$c8,$e9,$8a,$ab,$44,$65,$06,$27,$c0,$e1,$82,$a3
  711.     dc.b $7d,$5c,$3f,$1e,$f9,$d8,$bb,$9a,$75,$54,$37,$16,$f1,$d0,$b3,$92
  712.     dc.b $2e,$0f,$6c,$4d,$aa,$8b,$e8,$c9,$26,$07,$64,$45,$a2,$83,$e0,$c1
  713.     dc.b $1f,$3e,$5d,$7c,$9b,$ba,$d9,$f8,$17,$36,$55,$74,$93,$b2,$d1,$f0
  714.  
  715.     endc
  716. ;;;;
  717. ;
  718. ; The disk change interrupt handler glue code.
  719.  
  720.     ifne    0
  721.     xref    _DiskChangeHandler
  722.     xdef    _DiskChangeHandler0
  723.  
  724. _DiskChangeHandler0:
  725.     move.l    a1,-(sp)                ; is_Data
  726.     jsr    _DiskChangeHandler
  727.     lea    4(sp),sp
  728.     rts
  729.     endc
  730.  
  731.     end
  732.